# OneToManyAssociationConfiguration.java

    package org.codefilarete.stalactite.engine.configurer.onetomany;

    import java.util.Collection;
    import java.util.function.Supplier;

    import org.codefilarete.reflection.AccessorDefinition;
    import org.codefilarete.reflection.Mutator;
    import org.codefilarete.reflection.ReadWritePropertyAccessPoint;
    import org.codefilarete.stalactite.dsl.naming.ColumnNamingStrategy;
    import org.codefilarete.stalactite.dsl.naming.ForeignKeyNamingStrategy;
    import org.codefilarete.stalactite.dsl.naming.JoinColumnNamingStrategy;
    import org.codefilarete.stalactite.dsl.property.CascadeOptions;
    import org.codefilarete.stalactite.engine.runtime.ConfiguredRelationalPersister;
    import org.codefilarete.stalactite.sql.ddl.structure.PrimaryKey;
    import org.codefilarete.stalactite.sql.ddl.structure.Table;
    import org.codefilarete.tool.Reflections;

    /**
     * Class that stores elements necessary to one-to-many association configuration
     */
    class OneToManyAssociationConfiguration<SRC, TRGT, SRCID, TRGTID, C extends Collection<TRGT>, LEFTTABLE extends Table<LEFTTABLE>> {

    	private final OneToManyRelation<SRC, TRGT, TRGTID, C> oneToManyRelation;
    	private final ConfiguredRelationalPersister<SRC, SRCID> srcPersister;
    	private final PrimaryKey<LEFTTABLE, SRCID> leftPrimaryKey;
    	private final ForeignKeyNamingStrategy foreignKeyNamingStrategy;
    	private final JoinColumnNamingStrategy joinColumnNamingStrategy;
    	private final ColumnNamingStrategy indexColumnNamingStrategy;
    	private final ReadWritePropertyAccessPoint<SRC, C> collectionGetter;
    	private final String indexingColumnName;
    	private final Mutator<SRC, C> setter;
    	private final boolean orphanRemoval;
    	private final boolean writeAuthorized;
    	private final AccessorDefinition accessorDefinition;
    	private final Supplier<C> collectionFactory;

    	OneToManyAssociationConfiguration(OneToManyRelation<SRC, TRGT, TRGTID, C> oneToManyRelation,
    									  ConfiguredRelationalPersister<SRC, SRCID> srcPersister,
    									  PrimaryKey<LEFTTABLE, SRCID> leftPrimaryKey,
    									  ForeignKeyNamingStrategy foreignKeyNamingStrategy,
    									  JoinColumnNamingStrategy joinColumnNamingStrategy,
    									  ColumnNamingStrategy indexColumnNamingStrategy,
    									  String indexingColumnName,
    									  boolean orphanRemoval,
    									  boolean writeAuthorized) {
    		this.oneToManyRelation = oneToManyRelation;
    		this.srcPersister = srcPersister;
    		this.leftPrimaryKey = leftPrimaryKey;
    		this.foreignKeyNamingStrategy = foreignKeyNamingStrategy;
    		this.joinColumnNamingStrategy = joinColumnNamingStrategy;
    		this.indexColumnNamingStrategy = indexColumnNamingStrategy;
    		this.indexingColumnName = indexingColumnName;
    		this.collectionGetter = oneToManyRelation.getCollectionAccessor();
    		this.setter = collectionGetter;
    		this.orphanRemoval = orphanRemoval;
    		this.writeAuthorized = writeAuthorized;
    		this.accessorDefinition = AccessorDefinition.giveDefinition(this.oneToManyRelation.getCollectionAccessor());
    		this.collectionFactory = buildCollectionFactory();
    	}

    	private Supplier<C> buildCollectionFactory() {
    		Supplier<C> result = oneToManyRelation.getCollectionFactory();
    		if (result == null) {
    			result = Reflections.giveCollectionFactory((Class<C>) accessorDefinition.getMemberType());
    		}
    		return result;
    	}

    	public OneToManyRelation<SRC, TRGT, TRGTID, C> getOneToManyRelation() {
    		return oneToManyRelation;
    	}

    	public ConfiguredRelationalPersister<SRC, SRCID> getSrcPersister() {
    		return srcPersister;
    	}

    	public PrimaryKey<LEFTTABLE, SRCID> getLeftPrimaryKey() {
    		return leftPrimaryKey;
    	}

    	public ForeignKeyNamingStrategy getForeignKeyNamingStrategy() {
    		return foreignKeyNamingStrategy;
    	}

    	public JoinColumnNamingStrategy getJoinColumnNamingStrategy() {
    		return joinColumnNamingStrategy;
    	}

    	public ColumnNamingStrategy getIndexColumnNamingStrategy() {
    		return indexColumnNamingStrategy;
    	}

    	public String getIndexingColumnName() {
    		return indexingColumnName;
    	}

    	public ReadWritePropertyAccessPoint<SRC, C> getCollectionGetter() {
    		return collectionGetter;
    	}

    	public Mutator<SRC, C> getSetter() {
    		return setter;
    	}

    	public boolean isOrphanRemoval() {
    		return orphanRemoval;
    	}

    	public boolean isWriteAuthorized() {
    		return writeAuthorized;
    	}

    	public boolean isMaintainAssociationOnly() {
    		return oneToManyRelation.getRelationMode() == CascadeOptions.RelationMode.ASSOCIATION_ONLY;
    	}

    	/**
    	 * Equivalent to {@link org.codefilarete.stalactite.engine.configurer.onetomany.OneToManyRelation#getCollectionAccessor()}.
    	 * Collection access will be done through {@link OneToManyAssociationConfiguration#getCollectionGetter()} and {@link OneToManyAssociationConfiguration#getCollectionFactory()}
    	 */
    	public AccessorDefinition getAccessorDefinition() {
    		return accessorDefinition;
    	}

    	/**
    	 * Gives the collection factory used to instantiate relation field.
    	 *
    	 * @return the one given by {@link OneToManyRelation#getCollectionFactory()} or one deduced from member signature
    	 */
    	public Supplier<C> getCollectionFactory() {
    		return collectionFactory;
    	}
    }